package com.apes.fn.crm.ReturnVisit.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.crm.ReturnVisit.model.*;
import com.apes.fn.crm.ReturnVisit.repository.*;
import com.apes.fn.crm.customComplain.FnCustomComplain;
import com.apes.fn.crm.customComplain.FnCustomComplainRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.repository.RetailOrderItemRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.mq.MQUtil;
import com.apes.framework.plugin.mq.annotation.Consumer;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.hr.base.repository.EmployeeDao;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;


@Service("returnVisitService")
public class ReturnVisitService extends DomainService {

    @Autowired
    ReturnVisitRepository returnVisitRepository;
    @Autowired
    VisitCustomerExpandService visitCustomerExpandService;
    @Autowired
    VisitCustomerRoleExpandService visitCustomerRoleExpandService;
    @Autowired
    VisitConditionService visitConditionService;
    @Autowired
    EnumerationRepository enumerationRepository;
    @Autowired
    VisitCustomerExpandRepository visitCustomerExpandRepository;
    @Autowired
    VisitOperatorRepository visitOperatorRepository;
    @Autowired
    VisitConditionRepository visitConditionRepository;
    @Autowired
    RetailOrderRepository retailOrderRepository;
    @Autowired
    ProductRepository productRepository;
    @Autowired
    PartyRoleRepository partyRoleRepository;
    @Autowired
    AccessProviderRepository accessProviderRepository;
    @Autowired
    ReturnVisitItemRepository returnVisitItemRepository;
    @Autowired
    VisitHistoryRepository visitHistoryRepository;
    @Autowired
    FnCustomComplainRepository customComplainRepository;
    @Autowired
    RetailOrderItemRepository retailOrderItemRepository;
    @Autowired
    EmployeeDao employeeDao;
    /***
     * 创建
     */
    public ReturnVisit create(SimpleRequest request) {
        ReturnVisit returnVisit = request.getO(ReturnVisit.class);
        return returnVisitRepository.saveAndFlush(returnVisit);
    }

    /***
     * 修改
     */
    public ReturnVisit update(SimpleRequest request) {
        isValid(request, returnVisitRepository);
        ReturnVisit returnVisit = request.getO(ReturnVisit.class);
        return returnVisitRepository.saveAndFlush(returnVisit);
    }

    /***
     * 删除
     */
    public String delete(SimpleRequest request) {
        isValid(request, returnVisitRepository);
        ReturnVisit returnVisit = request.getO(ReturnVisit.class);
        returnVisitRepository.delete(returnVisit);
        return "删除成功！";
    }


    /***
     * 回访
     */
    public JSONObject visit(SimpleRequest request) {
        Map map = request.getMap();
        JSONObject visitState = (JSONObject) map.get("visitState");
        String state = visitState.getString("id");
        switch (state){
            case "finish":
                map.put("visitFailReason",null);
                map.put("nextVisitDate",null);
                break;
            case "end":
                map.put("nextVisitDate",null);
                map.put("visitSatisfaction",null);
                map.put("advice",null);
                break;
            case "again":
                map.put("visitSatisfaction",null);
                break;
                default:
                    break;
        }
        this.invoke("fn.returnVisit.visitUpdate", map);
        this.invoke("fn.visitHistory.create", map);
        this.invoke("fn.visitCustomerExpand.create", map);
        return new JSONObject();
    }


    public ReturnVisit visitUpdate(SimpleRequest request) {
        JSONObject tempJson = request.getJO();
        ReturnVisit returnVisit = returnVisitRepository.findOne((String) request.get("id"));
        String state = tempJson.getJSONObject("visitState").getString("id");
        if( state.equals("finish") ||
                state.equals("end")){
            returnVisit.setVisitedDate(new Date());
        }

        if( state.equals("again")){
            returnVisit.setNextVisitDate( DateUtil.parseTimestamp(tempJson.getString("nextVisitDate")));
        }

        returnVisit.setState(state);
        returnVisit.setVisitor(request.getPerson()); // 重新设置回访人


        return returnVisitRepository.saveAndFlush(returnVisit);
    }


    /***
     * 数据是否合法
     * @param request
     * @param repository
     */
    private Model isValid(SimpleRequest request, CustomRepository repository) {
        Model oldModel = (Model) repository.findOne((String) request.get("id"));
        if (oldModel == null) throw new RuntimeException("编码【" + request.get("id") + "】在系统中不存在。");
        if (oldModel.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        return oldModel;
    }


    /***
     * 获取回访历史
     */
    public Map getVisitHistory(SimpleRequest request) {
        List<VisitHistory> visitHistories = visitHistoryRepository.findAll(
                JpaDsl.toCriteriaByEq(
                        "returnVisit.mobile", request.get("mobile"),
                        "returnVisit.company.id", request.get("companyId")
                ),
                new Sort(Sort.Direction.ASC, "id")
        );
        return MapUtil.mapper(
                "visitHistory", visitHistories
        );
    }


    /***
     * 获取客诉历史
     */
    public Map getComplainHistory(SimpleRequest request) {
        List<FnCustomComplain> customComplains = customComplainRepository.findAll(
                JpaDsl.toCriteriaByEq(
                        "customerExpand.mobile", request.get("mobile"),
                        "company.id", request.get("companyId")
                ),
                new Sort(Sort.Direction.ASC, "id")
        );
        return MapUtil.mapper(
                "complainHistory", customComplains
        );
    }

    /***
     * 获取零售单明细
     */
    public Map getRetailOrderItem(SimpleRequest request) {
        Group group = new Group();
        List<Filter> filters = JpaDsl.toFilter(
                "order.id", "in", request.get("ids")
        );
        filters.get(0).setType("array");
        group.addFilters(filters);
        Sort sort = new Sort(Sort.Direction.DESC, "order.id");

        List<RetailOrderItem> retailOrderItems = retailOrderItemRepository.findAll(group.build(true), sort);

        return MapUtil.mapper(
                "retailOrderItem", retailOrderItems.stream().map(
                        retailOrderItem -> {
                            Map m = MapUtil.mapped(retailOrderItem);
                            m.put("id", retailOrderItem.getOrder().getId());
                            m.put("dateDone", DateUtil.format(retailOrderItem.getOrder().getDateDone(), DateUtil.SHOW_DATE_FORMAT));
                            m.put("serveType", retailOrderItem.getProduct().queryServeType().getName());
                            return m;
                        }
                ).toArray()
        );
    }

    private int getNextVisitPeriod() {
        Enumeration enumeration = enumerationRepository.findOne(JpaDsl.toCriteriaByEq(
                "type.id", "nextVisitPeriod"
        )).orElse(null);
        return enumeration != null ? Integer.parseInt(enumeration.getDescription()) : 15;
    }


    /***
     * 获取回访天数起（零售订单结算开始）
     */
    private int getVisitWaitPeriod() {
        Enumeration enumeration = enumerationRepository.findOne(JpaDsl.toCriteriaByEq(
                "type.id", "visitWaitPeriod"
        )).orElse(null);
        return enumeration != null ? Integer.parseInt(enumeration.getDescription()) : 3;
    }


    /***
     * 获取需回访的零售订单并执行
     */

    public List<Map> getWaitingForVisit(SimpleRequest request) {
        JSONObject tempJson = request.getJO();

        if(tempJson.get("taskDate") == null) throw new RuntimeException("请输入正确的执行时间");

        Date executeDate;
        if(tempJson.get("taskDate") instanceof Date) {
            executeDate = tempJson.getDate("taskDate");
        } else {
            try {
                executeDate = DateUtil.parse(tempJson.getString("taskDate"));
            } catch (Exception e) {
                throw new RuntimeException("请按照正确的时间格式传入，格式：yyyy-MM-dd");
            }
        }


        Date startDate = DateUtil.add(executeDate, 5, -getVisitWaitPeriod());
        Date endDate = DateUtil.add(executeDate, 5, -getVisitWaitPeriod() + 1);
        List<RetailOrder> retailOrders = retailOrderRepository.findAll(
                JpaDsl.toCriteria(
                    "dateDone", "GTE" , startDate,
                        "dateDone", "LT" , endDate,
                        "customerExpand.id", "NE", null,
                        "customerExpand.mobile", "NE", null,
                        "customerExpand.carLicense", "NE", null
                )
        );

        // 通过手机号对数据进行分组
        Map<String, List<RetailOrder>> groupByMobile = retailOrders.stream().collect(Collectors.groupingBy(
                retailOrder -> retailOrder.getCustomerExpand().getMobile()
        ));

        return groupByMobile.keySet().stream().map(key -> {

            List<RetailOrder> retailOrderList = groupByMobile.get(key);

            return MapUtil.mapper(
                    "ids", retailOrderList.stream().map(RetailOrder::getId).toArray(),
                    "executeDate", executeDate
            );
        }).collect(Collectors.toList());
    }

    public void returnVisitTest(SimpleRequest request){
        request.getJA().stream().forEach(item -> {
            SimpleRequest re = new SimpleRequest();
            re.setData(item);
            insertReturnVisit(re);
        });
    }

    /***
     * 插入数据
     */
    private void insertReturnVisit(SimpleRequest request) {
        JSONObject param = request.getJO();
        Date executeDate = param.getDate("executeDate");
        JSONArray ids = param.getJSONArray("ids");
        ids.stream().forEach(id -> {
            RetailOrder retailOrder = retailOrderRepository.findOne((String) id);
            insertReturnVisit(retailOrder, executeDate);
        });

    }

    private void insertReturnVisit(RetailOrder retailOrder, Date executeDate){
        AccessProvider accessProvider = retailOrder.getCompany().queryAccessProvider();
        retailOrder.getCustomerExpand().setVendorCode(accessProvider.getId());
        retailOrder.getCustomerExpand().setVendorName(accessProvider.getName());
        if( !insertPreRule(retailOrder)) return;
        insertRule(retailOrder, executeDate);
    }


    /***
     * 写入前置规则（定损报价 年审预约 ）
     * 1. 零售单来源（定损报价 年审预约 服务单 ）
     * 2. App 评价
     * 3. 单位车辆
     * 4. 会员回访标记 会员等级回访标记
     * 5. 是否满足回访金额
     */
    private boolean insertPreRule(RetailOrder retailOrder) {

        if( isCompanyCar(retailOrder) ) return false;
        if( isAvaluated(retailOrder) ) return false;
        if( !isCustomerNeedVisit(retailOrder) ) return false;
        if( !isPriceNeedVisit(retailOrder) ) return false;
        return true;
    }


    /***
     * 回访标记
     */
    private boolean isCustomerNeedVisit(RetailOrder retailOrder) {
        VisitCustomerRoleExpand visitCustomerRoleExpand = visitCustomerRoleExpandService.findByCustomerRolelId(
                retailOrder.getCustomerExpand().getUserRoleId()
        );
        VisitCustomerExpand visitCustomerExpand = visitCustomerExpandService.findByCustomerId(
                retailOrder.getCustomerExpand().getMobile(),  retailOrder.getCustomerExpand().getVendorCode()
        );

        if (visitCustomerRoleExpand != null && !visitCustomerRoleExpand.isVisitSign()) return false;
        if (visitCustomerExpand != null && visitCustomerExpand.isNotVisitSign()) return false;
        return true;
    }

    /***
     * 回访金额
     * serveType
     * qty
     * price
     */
    private boolean isPriceNeedVisit(RetailOrder retailOrder) {

        Map<String, List<RetailOrderItem>> groupByServeTypeId =retailOrder.getSaleItems().stream().collect(Collectors.groupingBy(saleItem -> {
            Product product = saleItem.getProduct();
            return product.queryServeType().getId();
        }));


        for (String key : groupByServeTypeId.keySet()) {

            List<RetailOrderItem> items = groupByServeTypeId.get(key);

            // 获取回访条件
            VisitCondition visitCondition = getVisitCondition(retailOrder.getCompany(), key);
            if (visitCondition == null) continue;

            // 合计品类总金额
            Double totalPrice = items.stream().map(item -> item.getPriceTotal()).reduce(0.0, (d1, d2) -> d1 + d2);


            if (totalPrice >= visitCondition.getTotal()) return true;
        }
        return false;
    }


    /***
     * App评价
     */
    private boolean isAvaluated(RetailOrder retailOrder) {
        /*** TODO：App评价接口对接 ***/
        return false;
    }


    /***
     * 单位车辆
     */
    private boolean isCompanyCar(RetailOrder retailOrder) {
        return retailOrder.getCustomerExpand() != null && retailOrder.getCustomerExpand().getUnitClientId() != null;
    }


    /***
     * 写入规则
     * 1. 判断是否存在未回访完成的单据
     * 2. 获取上次回访日期， 回访时间段
     * 3. 写入回访人
     */

    private void insertRule(RetailOrder retailOrder, Date executeDate) {
        /*** TODO: 明细表中写入车辆 ***/
        ReturnVisit returnVisit = getUndone(retailOrder);
        ReturnVisitItem returnVisitItem = Tools.toBean(ReturnVisitItem.class, MapUtil.mapper(
                "source", retailOrder.getId(),
                "sourceBusinessType", retailOrder.getInnerBusinessType(),
                "sourceBusinessTypeName", "零售订单",
                "consumeDate", retailOrder.getDateDone(),
                "customerExpand", retailOrder.getCustomerExpand()
        ));
        if (returnVisit != null) {
            returnVisitItem.setReturnVisit(returnVisit);
            returnVisitItem.setCompany(returnVisit.getCompany());
            returnVisitItem = returnVisitItemRepository.saveAndFlush(returnVisitItem);
            returnVisit.setVisitor(null);
            returnVisit.setVisitors(getVisitsOperator(retailOrder));
            returnVisit.getReturnVisitItems().add(returnVisitItem);
        } else {
            VisitOperator visitOperator = getVisitOperator( retailOrder.getCompany().getId(), retailOrder.getDept().getId());
            ArrayList returnVisitItems = new ArrayList();
            returnVisitItems.add(returnVisitItem);
            List<PartyRole> visitors = getVisitsOperator(retailOrder);

/*            PartyRole company = new PartyRole();
            PartyRole customer = new PartyRole();
            Dept dept = new Dept();
            company.setId(param.getJSONObject("company").getString("id"));
            dept.setId(param.getJSONObject("dept").getString("id"));
            customer.setId(param.getJSONObject("customer").getString("id"));*/
            // TODO : 增加额外的字段写入


            returnVisit = Tools.toBean(ReturnVisit.class, MapUtil.mapper(
                    "company", retailOrder.getCompany(),
                    "visitors", visitors,
                    "dept", retailOrder.getDept(),
                    "shouldVisitDate", getShouldVisitDate(retailOrder, executeDate),
                    "state", "create",
                    "mobile", retailOrder.getCustomerExpand().getMobile(),
                    "customerRoleName", retailOrder.getCustomerExpand().getUserRoleName(),
                    "returnVisitItems",returnVisitItems
            ));
        }
        if(retailOrder.getCustomerExpand().getCustomerLevelName() != null) returnVisit.setCustomerLevelName(retailOrder.getCustomerExpand().getCustomerLevelName());
        if(retailOrder.getCustomerExpand().getRealname() != null) returnVisit.setRealname(retailOrder.getCustomerExpand().getRealname());
        returnVisitRepository.saveAndFlush(returnVisit);

    }

    /**
     * 获取回访员
     * 根据部门查询岗位（店长助理，服务顾问）的在职员工作为回访员
     * 若查询不到在职人员时，则通过售后回访员查询
     * @param retailOrder
     * @return
     */
    private List<PartyRole> getVisitsOperator(RetailOrder retailOrder){
        List<PartyRole> visitors = new ArrayList<>();


        // 查询到对应部门的店长助理、服务顾问在职员工
        JSONObject param = new JSONObject(MapUtil.mapper("deptId", retailOrder.getDept().getId()));
        JSONArray jsonArray = employeeDao.partyRoleByPostAndDeptId(param);
        List<String> partyRoleIds = jsonArray.stream().map(item -> {
            JSONObject jo = (JSONObject) item;
            return jo.getString("PARTY_ROLE_ID");
        }).distinct().collect(Collectors.toList());
        if (!partyRoleIds.isEmpty()) visitors = partyRoleRepository.findAll(JpaDsl.toCriteria("id", "in", partyRoleIds));


        if (visitors.isEmpty()){
            // 未查询到对应部门的店长助理、服务顾问在职员工
            VisitOperator visitOperator = getVisitOperator( retailOrder.getCompany().getId(), retailOrder.getDept().getId());
            if (Objects.isNull(visitOperator)) return visitors;
            visitors.add(visitOperator.getVisitor());
        }

        return visitors;
    }

    /***
     * 获取未完成单据(处理中, 客户， 门店 )
     */
    private ReturnVisit getUndone(RetailOrder retailOrder) {
        ArrayList<String> states = new ArrayList();
        states.add("create");
        states.add("again");
        return returnVisitRepository.findOne(JpaDsl.toCriteria(
                "mobile", "EQ", retailOrder.getCustomerExpand().getMobile(),
                "state", "IN", states,
                "dept.id", "EQ", retailOrder.getDept().getId(),
                "company.id", "EQ", retailOrder.getCompany().getId()

        )).orElse(null);
    }

    /***
     * 获取会员扩展表
     */
    private VisitCustomerExpand getVisitCustomerExpand(RetailOrder retailOrder) {
        return visitCustomerExpandRepository.findOne(JpaDsl.toCriteriaByEq(
                "mobile", retailOrder.getCustomerExpand().getMobile(),
                "accessProvider.id", retailOrder.getCustomerExpand().getVendorCode()
        )).orElse(null);
    }

    /***
     * 获取回访人(接入商 + 门店 或者  单门店)
     */
    private VisitOperator getVisitOperator(String companyId, String deptId) {
        PartyRole company = partyRoleRepository.findOne(companyId);
        VisitOperator visitOperator = visitOperatorRepository.findOne(JpaDsl.toCriteriaByEq(
                "accessProvider", accessProviderRepository.findByCompany(company.getId()) ,
                "dept.id", deptId
        )).orElse(null);

        return visitOperator != null ? visitOperator : visitOperatorRepository.findOne(JpaDsl.toCriteriaByEq(
                "dept.id", deptId
        )).orElse(null);
    }

    /***
     * 获取回访条件
     */
    private VisitCondition getVisitCondition(PartyRole company, String serveTypeId) {
        VisitCondition visitCondition = visitConditionRepository.findOne(JpaDsl.toCriteriaByEq(
                "accessProvider", accessProviderRepository.findByCompany(company.getId()),
                "serveType.id", serveTypeId
        )).orElse(null);

        return visitCondition != null ? visitCondition : visitConditionRepository.findOne(JpaDsl.toCriteriaByEq(
                "serveType.id", serveTypeId
        )).orElse(null);
    }

    /***
     * 获取会员下次回访日期
     */
    private Date getShouldVisitDate(RetailOrder retailOrder, Date executeDate) {
        VisitCustomerExpand visitCustomerExpand = getVisitCustomerExpand(retailOrder);
        int nextVisitPeriod = getNextVisitPeriod(); // 回访间隔时间


        // 当前日结任务执行的后一天（应该回访的时间）
        Date shouldVisitDate = DateUtil.dateToDate(DateUtil.add(executeDate, 5, 1), DateUtil.SHOW_DATE_FORMAT);

        // 获取下次回访时间并格式化
        Date nextShouldVisitDate = visitCustomerExpand != null && visitCustomerExpand.getPrevVisitDate() != null ?
                DateUtil.add(visitCustomerExpand.getPrevVisitDate(), 5, nextVisitPeriod) : null;


        if(nextShouldVisitDate == null)  return shouldVisitDate; // 未回访过

        // 确认具体回访时间
        nextShouldVisitDate = DateUtil.dateToDate(nextShouldVisitDate, DateUtil.SHOW_DATE_FORMAT);
        return  nextShouldVisitDate.compareTo(shouldVisitDate) == -1 ? shouldVisitDate : nextShouldVisitDate;

    }

    /***
     * 关联待回访单号，来源单号进行查询
     */
    public Page<ReturnVisit> findAllRelate(SimpleRequest request) {
        Group group = findAllCore(request);
        return returnVisitRepository.findAll(group.build(true), JpaDsl.getPageable(request));
    }

    /***
     * 抽取的公共逻辑
     */
    private Group findAllCore(SimpleRequest request) {
        Group group = JpaDsl.getGroup(request);

        List<Filter> filters = group.getFilters();

        // 筛选出对应的id， 用于匹配 待回访单号，来源单号进行查询
        Filter filter = filters.stream().filter(item -> item.getField().equals("id")).findFirst().orElse(null);

        if (filter != null) {
            filters.remove(filter); // 移除当前选项

            Group idGroup = new Group();
            idGroup.setOperator("or");
            idGroup.addFilters(JpaDsl.toFilter(
                    "id", "EQ", filter.getValue(),
                    "returnVisitItems.source","EQ",filter.getValue()
            ));
            group.addGroup(idGroup);
        }

        // 只查询状态为创建和继续回访
        filter = new Filter();
        filter.setField("state");
        filter.setValue(Arrays.asList("create","again"));
        filter.setOperator("IN");
        filters.add(filter);
        return group;
    }

    /***
     * 写入前置规则
     * 1. 零售单来源（定损报价 年审预约 服务单 ）
     * 2. App 评价（待确认）
     * 3. 单位车辆
     * 4. 会员回访标记 会员等级回访标记
     * 5. 是否满足回访金额
     */
    /***
     * 写入规则
     * 1. 判断是否存在未回访完成的单据
     * 2. 获取上次回访日期， 回访时间段
     * 3. 写入回访人
     */


    /** 写入售后回访代办（100%）
     * 1. 获取回访人(接入商 + 门店 或者  单门店)
     * 2. 获取会员下次回访日期
     * 3. 获取未完成单据(处理中, 客户， 门店
     * 4. 获取会员扩展表
     * 5. 正常写入售后回访代办
     */

    /***
     * 售后回访（60%）
     * 1. 保存原始单据状态
     * 2. 保存回访历史
     * 3. 保存会员回访扩展表
     * 暂缺：对应的mapping和esb以及优化
     */
}
